home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / debug / signals.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  10.0 KB  |  318 lines

  1. (* DebugSignals
  2.    Support "historical" signals.
  3. *)
  4.  
  5. signature SIGNALS =
  6.   sig
  7.     datatype signal
  8.       = SIGHUP | SIGINT | SIGQUIT | SIGALRM | SIGTERM | SIGURG
  9.       | SIGCHLD | SIGIO | SIGWINCH | SIGUSR1 | SIGUSR2 | SIGVTALRM 
  10.       | SIGPROF | SIGTSTP | SIGCONT (* not yet supported *)
  11.       | SIGGC
  12.     val setHandler : (signal * ((int * unit cont) -> unit cont) option) -> unit
  13.     val inqHandler : signal -> ((int * unit cont) -> unit cont) option
  14.     val maskSignals : bool -> unit
  15.     val pause : unit -> unit
  16.     (* sleep until the next signal *)
  17.   end
  18.  
  19. signature DEBUG_SIGNALS = 
  20. sig
  21.   (* user-level functions *)
  22.   include SIGNALS 
  23.   (* debugger-control functions *)
  24.   val remember: unit -> DebugKernel.doers
  25.   val deliverableSignal: unit -> (signal*int) option
  26.       (* return current deliverable signal, if any *)
  27.   val handleSignal : unit -> DebugKernel.action option
  28.       (* return action to hanlde current deliverable signal, if any *)
  29.   val setSignal: signal -> unit (* add signal to pending vector *)
  30.   val clearSignal: signal -> unit (* remove signal from pending vector *)
  31.   val getSignal : signal -> int (* get current pending count *)
  32.   val forgetSignals : unit -> unit (* clear all signal counts *)
  33.   val deliverableHalting : unit -> bool (* should execution halt on the
  34.                        deliverable signal? *)
  35.   val setHalting :signal * bool -> unit (* set halting status *)
  36.   val permitSignals : bool -> unit  (* control inhibition flag *)
  37. end
  38.  
  39. structure DebugSignals : DEBUG_SIGNALS =
  40. struct
  41.   open Array List DebugUtil DebugKernel DebugStatic
  42.   infix 9 sub
  43.  
  44.   fun some x = x <> NONE
  45.  
  46.   (* are we recording? *)
  47.   fun recording () : bool = 
  48.       case !execMode of
  49.     RECORD _ => true
  50.       | _ => false
  51.  
  52.   structure S = System.Signals
  53.   open S
  54.   val nsigs = 16
  55.   exception UnimplementedSignal
  56.  
  57.   (* Convert SML signal names to run-time signal codes.  
  58.      For convenience, these should agree with S.Signals. *)
  59.   fun sig2code SIGHUP    = 0
  60.     | sig2code SIGINT    = (* 1 *) raise UnimplementedSignal
  61.     | sig2code SIGQUIT   = 2
  62.     | sig2code SIGALRM   = 3
  63.     | sig2code SIGTERM   = 4
  64.     | sig2code SIGURG    = 5
  65.     | sig2code SIGCHLD   = 6
  66.     | sig2code SIGIO     = 7
  67.     | sig2code SIGWINCH  = 8
  68.     | sig2code SIGUSR1   = 9
  69.     | sig2code SIGUSR2   = 10
  70.     | sig2code SIGTSTP   = (* 11 *) raise UnimplementedSignal
  71.     | sig2code SIGCONT   = (* 12 *) raise UnimplementedSignal
  72.     | sig2code SIGGC     = 13
  73.     | sig2code SIGVTALRM    = 14
  74.     | sig2code SIGPROF      = (* 15 *) raise UnimplementedSignal
  75.  
  76.   fun code2sig 0  = SIGHUP
  77.     | code2sig 1  = (* SIGINT *) raise UnimplementedSignal
  78.     | code2sig 2  = SIGQUIT
  79.     | code2sig 3  = SIGALRM
  80.     | code2sig 4  = SIGTERM
  81.     | code2sig 5  = SIGURG
  82.     | code2sig 6  = SIGCHLD
  83.     | code2sig 7  = SIGIO
  84.     | code2sig 8  = SIGWINCH
  85.     | code2sig 9  = SIGUSR1
  86.     | code2sig 10 = SIGUSR2
  87.     | code2sig 11 = (* SIGTSTP *) raise UnimplementedSignal
  88.     | code2sig 12 = (* SIGCONT *) raise UnimplementedSignal
  89.     | code2sig 13 = SIGGC
  90.     | code2sig 14 = SIGVTALRM
  91.     | code2sig 15 = (* SIGPROF *) raise UnimplementedSignal
  92.     | code2sig _ = debugPanic "signals.code2sig"
  93.  
  94.   type handler = (int * unit cont) -> unit cont
  95.  
  96.   (* number of signals of each type pending. *)
  97.   val pendvec = array(nsigs,0)  
  98.  
  99.   (* flag : signals permitted *)
  100.   val signalsOK = ref true
  101.  
  102.   (* flag: are we executing a user signal handler now? *)
  103.   val inHandler = ref false
  104.  
  105.   (* Our simulation of masking. Note that since SIGINT must never 
  106.      be masked indefinitely, we don't use S.maskSignals here. *)
  107.   val maskLevel = ref 0  
  108.  
  109.   (* is signal delivery enabled? *)
  110.   fun deliveryOK () = !signalsOK andalso 
  111.                            !maskLevel = 0 andalso not (!inHandler) 
  112.  
  113.   (* is there a deliverable signal? *)
  114.   fun deliverableSignal() : (signal*int) option =
  115.       let fun loop code = 
  116.       let val cnt = pendvec sub code
  117.       in if cnt > 0 then
  118.            SOME(code2sig code,cnt) 
  119.                   handle UnimplementedSignal => loop(code+1)
  120.          else loop(code+1)
  121.       end handle Subscript => NONE
  122.       in if deliveryOK() 
  123.        then loop 0
  124.          else NONE
  125.       end
  126.  
  127.   (* Force halt at next time step; idempotent function *)
  128.   fun signalHalt() = setTargetTime(currentTime() + 1) 
  129.  
  130.   fun checkSignalHalt() = 
  131.       if recording() andalso some(deliverableSignal()) then
  132.     signalHalt()
  133.       else ()
  134.  
  135.   (* Internal masking *)
  136.   fun permitSignals false = signalsOK := false
  137.     | permitSignals true = 
  138.          (signalsOK := true;
  139.       checkSignalHalt())
  140.  
  141.   (* User-level masking *)
  142.   fun maskSignals true = inc maskLevel
  143.     | maskSignals false = 
  144.       if !maskLevel > 0 then 
  145.            (dec maskLevel;
  146.          checkSignalHalt())
  147.       else ()
  148.  
  149.   (* Install true handler for all implemented signals.
  150.      This handler records signals received during recording.
  151.      If signals are not masked, the target time is reset to
  152.      force recording to halt at the next time-step.
  153.      N.B. It would be nice to do something about IO here; i.e., to
  154.      emulate the approach taken by the lower level to allow IO
  155.      waits to be interruptible.  Unfortunately, I don't see any way
  156.      to do this without exposing/simulating the inards of the IO package. *)
  157.  
  158.   fun trueHandler code (cnt,cont) =
  159.        (if recording() then
  160.       (update(pendvec,code,pendvec sub code + cnt);
  161.        if deliveryOK() then
  162.          signalHalt()
  163.        else ())
  164.     else ();
  165.     cont)
  166.  
  167.   (* We always keep true handler installed for termination signals, i.e., those
  168.      assigned default action DFL_TERM_NO_CORE in signal.c (except SIGINT,
  169.      which debugger programs are not allowed to use). 
  170.      If these signals occur when no handler is present, an empty default
  171.      handler will be used; by default they will cause a halt.
  172.      Other signals get true handler only when there is a user handler
  173.      installed for them, thus giving the default action assigned
  174.      in signal.c.  In particular, this means SIGQUIT will cause the
  175.      debugger system to die if no user handler is installed, and
  176.      SIGURG, SIGCHLD, SIGIO, SIGWINCH, and SIGGC will be ignored.
  177.      The user can still invoke these signals manually, in which case
  178.      they will also be handled by the empty default handler,
  179.      and, by default, cause a halt. *)
  180.   val keepTrueHandler = [SIGHUP,SIGALRM,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM]
  181.   val _ = 
  182.     app (fn signal => S.setHandler(signal,SOME(trueHandler (sig2code signal))))
  183.         keepTrueHandler
  184.  
  185.   (* Explicit pendvec control.  These functions should be called when
  186.      execMode is not RECORD to avoid access conflicts on pendvec. *)
  187.   fun setSignal signal : unit = 
  188.       let val code = sig2code signal
  189.       in if pendvec sub code = 0 then
  190.        resetKnownTime()
  191.          else();
  192.          update(pendvec,code,pendvec sub code + 1)
  193.       end
  194.       
  195.   fun clearSignal signal : unit =
  196.       let val code = sig2code signal
  197.       in if pendvec sub code > 0 then
  198.        resetKnownTime()
  199.      else();
  200.      update(pendvec,code,0)
  201.       end
  202.  
  203.   fun getSignal signal : int = 
  204.       let val code =sig2code signal
  205.       in pendvec sub code
  206.       end
  207.  
  208.   fun forgetSignals () : unit = ArrayExt.refill(pendvec,0)
  209.  
  210.   (* the user's handlers *)
  211.   val sigvec = array(nsigs,NONE:handler option)
  212.  
  213.   (* user version *)
  214.   fun setHandler (signal,handler) = 
  215.        let val code = sig2code signal (* may raise *)
  216.        in update(sigvec,code,handler);
  217.        case handler of
  218.          SOME _ => 
  219.            S.setHandler(signal,SOME (trueHandler code))
  220.        | NONE => 
  221.            if not (exists (fn h => sig2code h = code) keepTrueHandler) then
  222.          S.setHandler(signal,NONE)
  223.            else ()
  224.        end
  225.  
  226.   fun saveHandlers () =  ArrayExt.copy sigvec
  227.  
  228.   fun resetHandlers (newsigvec:handler option array) =
  229.       let fun loop n =
  230.         let val newh = newsigvec sub n
  231.         in setHandler(code2sig n,newh)
  232.                        handle UnimplementedSignal => ();
  233.            loop (n+1)
  234.         end handle Subscript => ()
  235.       in loop 0
  236.       end
  237.  
  238.   fun inqHandler signal = sigvec sub (sig2code signal)
  239.  
  240.   (* Track which signals should produce execution halts.
  241.      By default, halt iff there is no installed user handler;
  242.      user cna explicitly override default with setHalting. *)
  243.   val haltvec:bool option array = array(nsigs,NONE)
  244.   fun setHalting (signal,state:bool) : unit =
  245.       let val code = sig2code signal
  246.       in update(haltvec,code,SOME state)
  247.       end
  248.   fun deliverableHalting () : bool =
  249.       case deliverableSignal() of
  250.     SOME(signal,_) => 
  251.         let val code = sig2code signal
  252.         in case haltvec sub code of
  253.              SOME state => state
  254.            | NONE => (case sigvec sub code of
  255.                 SOME _ => false
  256.               | NONE => true)
  257.         end
  258.       | NONE => false
  259.  
  260.   fun pause () =
  261.       (* N.B. This doesn't work very well wrt/atomicity, but neither
  262.          does the built-in version! *)
  263.     case (!execMode) of
  264.       RECORD _ => S.pause ()
  265.     | REPLAY _ => ()
  266.     | STOP => S.pause ()
  267.  
  268.  
  269.   (* Return action to handle current deliverable signal, if any.  
  270.      Successful call clears pending signal. *)
  271.   fun handleSignal ()  =
  272.      case deliverableSignal() of
  273.        SOME (signal,cnt) => 
  274.        let val code = sig2code signal
  275.            fun handlerAction () : unit =
  276.            (dbgprint (implode["*sighandle ",makestring code," ",
  277.                     makestring(currentTime()), "\n"]);
  278.             inHandler := true;
  279.             let val startTime = (pseudoEvent{evn=pseudoEvn SIGSTARTev,
  280.                              forced=false,
  281.                              args=nil};
  282.                      currentTime())
  283.             in callcc(fn cont =>
  284.                  let val cont' = 
  285.                  case sigvec sub code of
  286.                      SOME userHandler => 
  287.                     userHandler(cnt,cont)
  288.                    | NONE => cont (* empty handler *)
  289.                  in inHandler := false;
  290.                 (* set up for possible further signals *)
  291.                 checkSignalHalt();
  292.                 throw cont' ()
  293.                  end);
  294.             pseudoEvent{evn=pseudoEvn SIGENDev,
  295.                     forced=false,
  296.                     args=[System.Unsafe.cast startTime]}
  297.             end)
  298.        in update(pendvec,code,0); (* don't worry about access conflicts *)
  299.           SOME handlerAction
  300.        end
  301.      | NONE => NONE
  302.  
  303.   fun remember() =
  304.     let val savedHandlers = saveHandlers()
  305.         val savedLevel = !maskLevel
  306.     val savedInHandler = !inHandler
  307.     fun reset _ = 
  308.         (resetHandlers savedHandlers; 
  309.          maskLevel := savedLevel;
  310.          inHandler := savedInHandler)
  311.     in {redo=reset,undo=reset}
  312.     end
  313.  
  314. end
  315.  
  316.  
  317.  
  318.